home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gdevwpr2.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  43.6 KB  |  1,495 lines

  1. /* Copyright (C) 1989, 2000 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gdevwpr2.c,v 1.5 2000/09/19 19:00:23 lpd Exp $ */
  20. /*
  21.  * Microsoft Windows 3.n printer driver for Ghostscript.
  22.  * Original version by Russell Lang and
  23.  * L. Peter Deutsch, Aladdin Enterprises.
  24.  * Modified by rjl 1995-03-29 to use BMP printer code
  25.  * Modified by Pierre Arnaud 1999-02-18 (see description below)
  26.  * Modified by lpd 1999-04-03 for compatibility with Borland C++ 4.5.
  27.  * Modified by Pierre Arnaud 1999-10-03 (accept b&w printing on color printers).
  28.  * Modified by Pierre Arnaud 1999-11-20 (accept lower resolution)
  29.  * Bug fixed by Pierre Arnaud 2000-03-09 (win_pr2_put_params error when is_open)
  30.  * Bug fixed by Pierre Arnaud 2000-03-20 (win_pr2_set_bpp did not set anti_alias)
  31.  * Bug fixed by Pierre Arnaud 2000-03-22 (win_pr2_set_bpp depth was wrong)
  32.  */
  33.  
  34. /* This driver uses the printer default size and resolution and
  35.  * ignores page size and resolution set using -gWIDTHxHEIGHT and
  36.  * -rXxY.  You must still set the correct PageSize to get the
  37.  * correct clipping path.
  38.  * The code in win_pr2_getdc() does try to set the printer page
  39.  * size from the PostScript PageSize, but it isn't working
  40.  * reliably at the moment.
  41.  *
  42.  * This driver doesn't work with some Windows printer drivers.
  43.  * The reason is unknown.  All printers to which I have access
  44.  * work.
  45.  *
  46.  * rjl 1997-11-20
  47.  */
  48.  
  49. /* Additions by Pierre Arnaud (Pierre.Arnaud@iname.com) 1992-11-20
  50.  *
  51.  * The driver has been extended in order to provide some run-time
  52.  * feed-back about the default Windows printer and to give the user
  53.  * the opportunity to select the printer's properties before the
  54.  * device gets opened (and any spooling starts).
  55.  *
  56.  * The driver returns an additional property named "UserSettings".
  57.  * This is a dictionary which contens are valid only after setting
  58.  * the QueryUser property (see below). The UserSettings dict contains
  59.  * the following keys:
  60.  *
  61.  *  DocumentRange  [begin end]        (int array, can be set)
  62.  *    Defines the range of pages in the document; [1 10] would
  63.  *    describe a document starting at page 1 and ending at page 10.
  64.  *
  65.  *  SelectedRange  [begin end]        (int array, can be set)
  66.  *    Defines the pages the user wants to print.
  67.  *
  68.  *  MediaSize       [width height]    (float array, read only)
  69.  *    Current printer's media size.
  70.  *
  71.  *  Copies       n            (integer, can be set)
  72.  *    User selected number of copies.
  73.  *
  74.  *  PrintCopies    n            (integer, read only)
  75.  *    Number of copies which must be printed by Ghostscript itself.
  76.  *    This is still experimental.
  77.  *
  78.  *  DocumentName   name            (string, can be set)
  79.  *    Name to be associated with the print job.
  80.  *
  81.  *  UserChangedSettings            (bool, read only)
  82.  *    Set to 'true' if the last QueryUser operation succeeded.
  83.  *
  84.  *  Paper       n            (integer, can be set)
  85.  *    Windows paper selection (0 = automatic).
  86.  *
  87.  *  Orient       n            (integer, can be set)
  88.  *    Windows paper orientation (0 = automatic).
  89.  *
  90.  *  Color       n            (integer, can be set)
  91.  *    Windows color (0 = automatic, 1 = monochrome, 2 = color).
  92.  *
  93.  *  MaxResolution  n            (integer, can be set)
  94.  *    Maximum resolution in pixels pet inch (0 = no maximum). If
  95.  *    the printer has a higher resolution than the maximum, trim
  96.  *    the used resolution to the best one (dpi_chosen <= dpi_max,
  97.  *    with dpi_chosen = dpi_printer / ratio).
  98.  */
  99.  
  100. /* Supported printer parameters are :
  101.  *
  102.  *  -dBitsPerPixel=n
  103.  *     Override what the Window printer driver returns.
  104.  *
  105.  *  -dNoCancel
  106.  *     Don't display cancel dialog box.  Useful for unattended or
  107.  *     console EXE operation.
  108.  *
  109.  *  -dQueryUser=n
  110.  *     Query user interactively for the destination printer, before
  111.  *     the device gets opened. This fills in the UserSettings dict
  112.  *     and the OutputFile name properties. The following values are
  113.  *     supported for n:
  114.  *     1 => show standard Print dialog
  115.  *     2 => show Print Setup dialog instead
  116.  *     3 => select default printer
  117.  *     other, does nothing
  118.  *
  119.  * The /Duplex & /Tumble keys of the setpagedevice dict are supported
  120.  * if the Windows printer supports duplex printing.
  121.  */
  122.  
  123. #include "gdevprn.h"
  124. #include "gdevpccm.h"
  125.  
  126. #include "windows_.h"
  127. #include <shellapi.h>
  128. #include "gp_mswin.h"
  129.  
  130. #include "gp.h"
  131. #include "commdlg.h"
  132.  
  133.  
  134. /* Make sure we cast to the correct structure type. */
  135. typedef struct gx_device_win_pr2_s gx_device_win_pr2;
  136.  
  137. #undef wdev
  138. #define wdev ((gx_device_win_pr2 *)dev)
  139.  
  140. /* Device procedures */
  141.  
  142. /* See gxdevice.h for the definitions of the procedures. */
  143. private dev_proc_open_device(win_pr2_open);
  144. private dev_proc_close_device(win_pr2_close);
  145. private dev_proc_print_page(win_pr2_print_page);
  146. private dev_proc_map_rgb_color(win_pr2_map_rgb_color);
  147. private dev_proc_map_color_rgb(win_pr2_map_color_rgb);
  148. private dev_proc_get_params(win_pr2_get_params);
  149. private dev_proc_put_params(win_pr2_put_params);
  150.  
  151. private void win_pr2_set_bpp(gx_device * dev, int depth);
  152.  
  153. private const gx_device_procs win_pr2_procs =
  154. prn_color_params_procs(win_pr2_open, gdev_prn_output_page, win_pr2_close,
  155.                win_pr2_map_rgb_color, win_pr2_map_color_rgb,
  156.                win_pr2_get_params, win_pr2_put_params);
  157.  
  158.  
  159. /* The device descriptor */
  160. typedef struct gx_device_win_pr2_s gx_device_win_pr2;
  161. struct gx_device_win_pr2_s {
  162.     gx_device_common;
  163.     gx_prn_device_common;
  164.     HDC hdcprn;
  165.     bool nocancel;
  166.  
  167.     int doc_page_begin;        /* first page number in document */
  168.     int doc_page_end;        /* last page number in document */
  169.     int user_page_begin;    /* user's choice: first page to print */
  170.     int user_page_end;        /* user's choice: last page to print */
  171.     int user_copies;        /* user's choice: number of copies */
  172.     int print_copies;        /* number of times GS should print each page */
  173.     float user_media_size[2];    /* width/height of media selected by user */
  174.     char doc_name[200];        /* name of document for the spooler */
  175.     char paper_name[64];    /* name of selected paper format */
  176.     bool user_changed_settings;    /* true if user validated dialog */
  177.     int user_paper;        /* user's choice: paper format */
  178.     int user_orient;        /* user's choice: paper orientation */
  179.     int user_color;        /* user's choice: color format */
  180.     int max_dpi;        /* maximum resolution in DPI */
  181.     int ratio;            /* stretch ratio when printing */
  182.     int selected_bpp;        /* selected bpp, memorised by win_pr2_set_bpp */
  183.  
  184.     HANDLE win32_hdevmode;    /* handle to device mode information */
  185.     HANDLE win32_hdevnames;    /* handle to device names information */
  186.  
  187.     DLGPROC lpfnAbortProc;
  188.     DLGPROC lpfnCancelProc;
  189.  
  190.     gx_device_win_pr2* original_device;    /* used to detect copies */
  191. };
  192.  
  193. gx_device_win_pr2 far_data gs_mswinpr2_device =
  194. {
  195.     prn_device_std_body(gx_device_win_pr2, win_pr2_procs, "mswinpr2",
  196.               DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, 72.0, 72.0,
  197.             0, 0, 0, 0,
  198.             0, win_pr2_print_page),        /* depth = 0 */
  199.     0,                /* hdcprn */
  200.     0,                /* nocancel */
  201.     0,                /* doc_page_begin */
  202.     0,                /* doc_page_end */
  203.     0,                /* user_page_begin */
  204.     0,                /* user_page_end */
  205.     1,                /* user_copies */
  206.     1,                /* print_copies */
  207.     { 0.0, 0.0 },        /* user_media_size */
  208.     { 0 },            /* doc_name */
  209.     { 0 },            /* paper_name */
  210.     0,                /* user_changed_settings */
  211.     0,                /* user_paper */
  212.     0,                /* user_orient */
  213.     0,                /* user_color */
  214.     0,                /* max_dpi */
  215.     0,                /* ratio */
  216.     0,                /* selected_bpp */
  217.     NULL,            /* win32_hdevmode */
  218.     NULL,            /* win32_hdevnames */
  219.     NULL,            /* lpfnAbortProc */
  220.     NULL,            /* lpfnCancelProc */
  221.     NULL            /* original_device */
  222. };
  223.  
  224. /********************************************************************************/
  225.  
  226. private int win_pr2_getdc(gx_device_win_pr2 * dev);
  227. private int win_pr2_update_dev(gx_device_win_pr2 * dev, LPDEVMODE pdevmode);
  228. private int win_pr2_update_win(gx_device_win_pr2 * dev, LPDEVMODE pdevmode);
  229. private int win_pr2_print_setup_interaction(gx_device_win_pr2 * dev, int mode);
  230. private int win_pr2_write_user_settings(gx_device_win_pr2 * dev, gs_param_list * plist);
  231. private int win_pr2_read_user_settings(gx_device_win_pr2 * dev, gs_param_list * plist);
  232. private void win_pr2_copy_check(gx_device_win_pr2 * dev);
  233.  
  234. /********************************************************************************/
  235.  
  236. /* Open the win_pr2 driver */
  237. private int
  238. win_pr2_open(gx_device * dev)
  239. {
  240.     int code;
  241.     int depth;
  242.     PRINTDLG pd;
  243.     POINT offset;
  244.     POINT size;
  245.     float m[4];
  246.     FILE *pfile;
  247.     DOCINFO docinfo;
  248.     float ratio = 1.0;
  249.     
  250.     win_pr2_copy_check(wdev);
  251.  
  252.     if ((!wdev->nocancel) && (hDlgModeless)) {
  253.     /* device cannot opened twice since only one hDlgModeless */
  254.     fprintf(stderr, "Can't open mswinpr2 device twice\n");
  255.     return gs_error_limitcheck;
  256.     }
  257.  
  258.     /* get a HDC for the printer */
  259.     if ((wdev->win32_hdevmode) &&
  260.     (wdev->win32_hdevnames)) {
  261.     /* The user has already had the opportunity to choose the output */
  262.     /* file interactively. Just use the specified parameters. */
  263.     
  264.     LPDEVMODE devmode = (LPDEVMODE) GlobalLock(wdev->win32_hdevmode);
  265.     LPDEVNAMES devnames = (LPDEVNAMES) GlobalLock(wdev->win32_hdevnames);
  266.     
  267.     const char* driver = (char*)(devnames)+(devnames->wDriverOffset);
  268.     const char* device = (char*)(devnames)+(devnames->wDeviceOffset);
  269.     const char* output = (char*)(devnames)+(devnames->wOutputOffset);
  270.     
  271.     wdev->hdcprn = CreateDC(driver, device, output, devmode);
  272.     
  273.     GlobalUnlock(wdev->win32_hdevmode);
  274.     GlobalUnlock(wdev->win32_hdevnames);
  275.     
  276.     if (wdev->hdcprn == NULL) {
  277.         return gs_error_Fatal;
  278.     }
  279.     
  280.     } else if (!win_pr2_getdc(wdev)) {
  281.     /* couldn't get a printer from -sOutputFile= */
  282.     /* Prompt with dialog box */
  283.     
  284.     LPDEVMODE devmode = NULL;
  285.     memset(&pd, 0, sizeof(pd));
  286.     
  287.     pd.lStructSize = sizeof(pd);
  288.     pd.hwndOwner = hwndtext;
  289.     pd.Flags = PD_RETURNDC;
  290.     pd.nMinPage = wdev->doc_page_begin;
  291.     pd.nMaxPage = wdev->doc_page_end;
  292.     pd.nFromPage = wdev->user_page_begin;
  293.     pd.nToPage = wdev->user_page_end;
  294.     pd.nCopies = wdev->user_copies;
  295.     
  296.     if (!PrintDlg(&pd)) {
  297.         /* device not opened - exit ghostscript */
  298.         return gs_error_Fatal;    /* exit Ghostscript cleanly */
  299.     }
  300.     
  301.     devmode = GlobalLock(pd.hDevMode);
  302.     win_pr2_update_dev(wdev,devmode);
  303.     GlobalUnlock(pd.hDevMode);
  304.     
  305.     if (wdev->win32_hdevmode)
  306.         GlobalFree(wdev->win32_hdevmode);
  307.     if (wdev->win32_hdevnames)
  308.         GlobalFree(wdev->win32_hdevnames);
  309.     
  310.     wdev->hdcprn = pd.hDC;
  311.     wdev->win32_hdevmode = pd.hDevMode;
  312.     wdev->win32_hdevnames = pd.hDevNames;
  313.     
  314.     pd.hDevMode = NULL;
  315.     pd.hDevNames = NULL;
  316.     }
  317.     if (!(GetDeviceCaps(wdev->hdcprn, RASTERCAPS) != RC_DIBTODEV)) {
  318.     fprintf(stderr, "Windows printer does not have RC_DIBTODEV\n");
  319.     DeleteDC(wdev->hdcprn);
  320.     return gs_error_limitcheck;
  321.     }
  322.     /* initialise printer, install abort proc */
  323. #ifdef __WIN32__
  324.     wdev->lpfnAbortProc = (DLGPROC) AbortProc;
  325. #else
  326. #ifdef __DLL__
  327.     wdev->lpfnAbortProc = (DLGPROC) GetProcAddress(phInstance, "AbortProc");
  328. #else
  329.     wdev->lpfnAbortProc = (DLGPROC) MakeProcInstance((FARPROC) AbortProc, phInstance);
  330. #endif
  331. #endif
  332.     SetAbortProc(wdev->hdcprn, (ABORTPROC) wdev->lpfnAbortProc);
  333.  
  334.     /*
  335.      * Some versions of the Windows headers include lpszDatatype and fwType,
  336.      * and some don't.  Since we want to set these fields to zero anyway,
  337.      * we just start by zeroing the whole structure.
  338.      */
  339.     memset(&docinfo, 0, sizeof(docinfo));
  340.     docinfo.cbSize = sizeof(docinfo);
  341.     docinfo.lpszDocName = wdev->doc_name;
  342.     /*docinfo.lpszOutput = NULL;*/
  343.     /*docinfo.lpszDatatype = NULL;*/
  344.     /*docinfo.fwType = 0;*/
  345.  
  346.     if (docinfo.lpszDocName[0] == 0) {
  347.     docinfo.lpszDocName = "Ghostscript output";
  348.     }
  349.  
  350.     if (StartDoc(wdev->hdcprn, &docinfo) <= 0) {
  351.     fprintf(stderr, "Printer StartDoc failed (error %08x)\n", GetLastError());
  352. #if !defined(__WIN32__) && !defined(__DLL__)
  353.     FreeProcInstance((FARPROC) wdev->lpfnAbortProc);
  354. #endif
  355.     DeleteDC(wdev->hdcprn);
  356.     return gs_error_limitcheck;
  357.     }
  358.     
  359.     dev->x_pixels_per_inch = (float)GetDeviceCaps(wdev->hdcprn, LOGPIXELSX);
  360.     dev->y_pixels_per_inch = (float)GetDeviceCaps(wdev->hdcprn, LOGPIXELSY);
  361.     
  362.     wdev->ratio = 1;
  363.     
  364.     if (wdev->max_dpi > 50) {
  365.     
  366.     float dpi_x = dev->x_pixels_per_inch;
  367.     float dpi_y = dev->y_pixels_per_inch;
  368.     
  369.     while ((dev->x_pixels_per_inch > wdev->max_dpi)
  370.         || (dev->y_pixels_per_inch > wdev->max_dpi)) {
  371.         ratio += 1.0;
  372.         wdev->ratio ++;
  373.         dev->x_pixels_per_inch = dpi_x / ratio;
  374.         dev->y_pixels_per_inch = dpi_y / ratio;
  375.     }
  376.     }
  377.     
  378.     size.x = GetDeviceCaps(wdev->hdcprn, PHYSICALWIDTH);
  379.     size.y = GetDeviceCaps(wdev->hdcprn, PHYSICALHEIGHT);
  380.     gx_device_set_width_height(dev, (int)(size.x / ratio), (int)(size.y / ratio));
  381.     offset.x = GetDeviceCaps(wdev->hdcprn, PHYSICALOFFSETX);
  382.     offset.y = GetDeviceCaps(wdev->hdcprn, PHYSICALOFFSETY);
  383.     
  384.     /* m[] gives margins in inches */
  385.     m[0] /*left   */ = offset.x / dev->x_pixels_per_inch / ratio;
  386.     m[3] /*top    */ = offset.y / dev->y_pixels_per_inch / ratio;
  387.     m[2] /*right  */ = (size.x - offset.x - GetDeviceCaps(wdev->hdcprn, HORZRES)) / dev->x_pixels_per_inch / ratio;
  388.     m[1] /*bottom */ = (size.y - offset.y - GetDeviceCaps(wdev->hdcprn, VERTRES)) / dev->y_pixels_per_inch / ratio;
  389.     gx_device_set_margins(dev, m, true);
  390.     
  391.     depth = dev->color_info.depth;
  392.     if (depth == 0) {
  393.     /* Set parameters that were unknown before opening device */
  394.     /* Find out if the device supports color */
  395.     /* We recognize 1, 4 (but use only 3), 8 and 24 bit color devices */
  396.     depth = GetDeviceCaps(wdev->hdcprn, PLANES) * GetDeviceCaps(wdev->hdcprn, BITSPIXEL);
  397.     }
  398.     win_pr2_set_bpp(dev, depth);
  399.  
  400.     /* gdev_prn_open opens a temporary file which we don't want */
  401.     /* so we specify the name now so we can delete it later */
  402.     pfile = gp_open_scratch_file(gp_scratch_file_name_prefix,
  403.                  wdev->fname, "wb");
  404.     fclose(pfile);
  405.     code = gdev_prn_open(dev);
  406.     /* delete unwanted temporary file */
  407.     unlink(wdev->fname);
  408.  
  409.     if (!wdev->nocancel) {
  410.     /* inform user of progress with dialog box and allow cancel */
  411. #ifdef __WIN32__
  412.     wdev->lpfnCancelProc = (DLGPROC) CancelDlgProc;
  413. #else
  414. #ifdef __DLL__
  415.     wdev->lpfnCancelProc = (DLGPROC) GetProcAddress(phInstance, "CancelDlgProc");
  416. #else
  417.     wdev->lpfnCancelProc = (DLGPROC) MakeProcInstance((FARPROC) CancelDlgProc, phInstance);
  418. #endif
  419. #endif
  420.     hDlgModeless = CreateDialog(phInstance, "CancelDlgBox",
  421.                     hwndtext, wdev->lpfnCancelProc);
  422.     ShowWindow(hDlgModeless, SW_HIDE);
  423.     }
  424.     return code;
  425. };
  426.  
  427. /* Close the win_pr2 driver */
  428. private int
  429. win_pr2_close(gx_device * dev)
  430. {
  431.     int code;
  432.     int aborted = FALSE;
  433.  
  434.     win_pr2_copy_check(wdev);
  435.  
  436.     /* Free resources */
  437.  
  438.     if (!wdev->nocancel) {
  439.     if (!hDlgModeless)
  440.         aborted = TRUE;
  441.     else
  442.         DestroyWindow(hDlgModeless);
  443.     hDlgModeless = 0;
  444. #if !defined(__WIN32__) && !defined(__DLL__)
  445.     FreeProcInstance((FARPROC) wdev->lpfnCancelProc);
  446. #endif
  447.     }
  448.     if (aborted)
  449.     AbortDoc(wdev->hdcprn);
  450.     else
  451.     EndDoc(wdev->hdcprn);
  452.  
  453. #if !defined(__WIN32__) && !defined(__DLL__)
  454.     FreeProcInstance((FARPROC) wdev->lpfnAbortProc);
  455. #endif
  456.     DeleteDC(wdev->hdcprn);
  457.  
  458.     if (wdev->win32_hdevmode != NULL) {
  459.     GlobalFree(wdev->win32_hdevmode);
  460.     wdev->win32_hdevmode = NULL;
  461.     }
  462.     if (wdev->win32_hdevnames != NULL) {
  463.     GlobalFree(wdev->win32_hdevnames);
  464.     wdev->win32_hdevnames = NULL;
  465.     }
  466.  
  467.     code = gdev_prn_close(dev);
  468.     return code;
  469. }
  470.  
  471.  
  472. /* ------ Internal routines ------ */
  473.  
  474. #undef wdev
  475. #define wdev ((gx_device_win_pr2 *)pdev)
  476.  
  477. /********************************************************************************/
  478.  
  479. /* ------ Private definitions ------ */
  480.  
  481.  
  482. /* new win_pr2_print_page routine */
  483.  
  484. /* Write BMP header to memory, then send bitmap to printer */
  485. /* one scan line at a time */
  486. private int
  487. win_pr2_print_page(gx_device_printer * pdev, FILE * file)
  488. {
  489.     int raster = gdev_prn_raster(pdev);
  490.  
  491.     /* BMP scan lines are padded to 32 bits. */
  492.     ulong bmp_raster = raster + (-raster & 3);
  493.     ulong bmp_raster_multi;
  494.     int scan_lines, yslice, lines, i;
  495.     int width;
  496.     int depth = pdev->color_info.depth;
  497.     byte *row;
  498.     int y;
  499.     int code = 0;        /* return code */
  500.     MSG msg;
  501.     char dlgtext[32];
  502.     HGLOBAL hrow;
  503.     int ratio = ((gx_device_win_pr2 *)pdev)->ratio;
  504.  
  505.     struct bmi_s {
  506.     BITMAPINFOHEADER h;
  507.     RGBQUAD pal[256];
  508.     } bmi;
  509.  
  510.     scan_lines = dev_print_scan_lines(pdev);
  511.     width = (int)(pdev->width - ((dev_l_margin(pdev) + dev_r_margin(pdev) -
  512.                   dev_x_offset(pdev)) * pdev->x_pixels_per_inch));
  513.  
  514.     yslice = 65535 / bmp_raster;    /* max lines in 64k */
  515.     bmp_raster_multi = bmp_raster * yslice;
  516.     hrow = GlobalAlloc(0, bmp_raster_multi);
  517.     row = GlobalLock(hrow);
  518.     if (row == 0)        /* can't allocate row buffer */
  519.     return_error(gs_error_VMerror);
  520.  
  521.     /* Write the info header. */
  522.  
  523.     bmi.h.biSize = sizeof(bmi.h);
  524.     bmi.h.biWidth = pdev->width;    /* wdev->mdev.width; */
  525.     bmi.h.biHeight = yslice;
  526.     bmi.h.biPlanes = 1;
  527.     bmi.h.biBitCount = pdev->color_info.depth;
  528.     bmi.h.biCompression = 0;
  529.     bmi.h.biSizeImage = 0;    /* default */
  530.     bmi.h.biXPelsPerMeter = 0;    /* default */
  531.     bmi.h.biYPelsPerMeter = 0;    /* default */
  532.  
  533.     StartPage(wdev->hdcprn);
  534.     
  535.     /* Write the palette. */
  536.  
  537.     if (depth <= 8) {
  538.     int i;
  539.     gx_color_value rgb[3];
  540.     LPRGBQUAD pq;
  541.  
  542.     bmi.h.biClrUsed = 1 << depth;
  543.     bmi.h.biClrImportant = 1 << depth;
  544.     for (i = 0; i != 1 << depth; i++) {
  545.         (*dev_proc(pdev, map_color_rgb)) ((gx_device *) pdev,
  546.                           (gx_color_index) i, rgb);
  547.         pq = &bmi.pal[i];
  548.         pq->rgbRed = gx_color_value_to_byte(rgb[0]);
  549.         pq->rgbGreen = gx_color_value_to_byte(rgb[1]);
  550.         pq->rgbBlue = gx_color_value_to_byte(rgb[2]);
  551.         pq->rgbReserved = 0;
  552.     }
  553.     } else {
  554.     bmi.h.biClrUsed = 0;
  555.     bmi.h.biClrImportant = 0;
  556.     }
  557.  
  558.     if (!wdev->nocancel) {
  559.     sprintf(dlgtext, "Printing page %d", (int)(pdev->PageCount) + 1);
  560.     SetWindowText(GetDlgItem(hDlgModeless, CANCEL_PRINTING), dlgtext);
  561.     ShowWindow(hDlgModeless, SW_SHOW);
  562.     }
  563.     for (y = 0; y < scan_lines;) {
  564.     /* copy slice to row buffer */
  565.     if (y > scan_lines - yslice)
  566.         lines = scan_lines - y;
  567.     else
  568.         lines = yslice;
  569.     for (i = 0; i < lines; i++)
  570.         gdev_prn_copy_scan_lines(pdev, y + i,
  571.                   row + (bmp_raster * (lines - 1 - i)), raster);
  572.     
  573.     if (ratio > 1) {
  574.         StretchDIBits(wdev->hdcprn, 0, y*ratio, pdev->width*ratio, lines*ratio,
  575.               0, 0, pdev->width, lines,
  576.               row,
  577.               (BITMAPINFO FAR *) & bmi, DIB_RGB_COLORS, SRCCOPY);
  578.     } else {
  579.         SetDIBitsToDevice(wdev->hdcprn, 0, y, pdev->width, lines,
  580.                   0, 0, 0, lines,
  581.                   row,
  582.                   (BITMAPINFO FAR *) & bmi, DIB_RGB_COLORS);
  583.     }
  584.     y += lines;
  585.  
  586.     if (!wdev->nocancel) {
  587.         /* inform user of progress */
  588.         sprintf(dlgtext, "%d%% done", (int)(y * 100L / scan_lines));
  589.         SetWindowText(GetDlgItem(hDlgModeless, CANCEL_PCDONE), dlgtext);
  590.     }
  591.     /* process message loop */
  592.     while (PeekMessage(&msg, hDlgModeless, 0, 0, PM_REMOVE)) {
  593.         if ((hDlgModeless == 0) || !IsDialogMessage(hDlgModeless, &msg)) {
  594.         TranslateMessage(&msg);
  595.         DispatchMessage(&msg);
  596.         }
  597.     }
  598.     if ((!wdev->nocancel) && (hDlgModeless == 0)) {
  599.         /* user pressed cancel button */
  600.         break;
  601.     }
  602.     }
  603.  
  604.     if ((!wdev->nocancel) && (hDlgModeless == 0))
  605.     code = gs_error_Fatal;    /* exit Ghostscript cleanly */
  606.     else {
  607.     /* push out the page */
  608.     if (!wdev->nocancel)
  609.         SetWindowText(GetDlgItem(hDlgModeless, CANCEL_PCDONE),
  610.               "Ejecting page...");
  611.     EndPage(wdev->hdcprn);
  612.     if (!wdev->nocancel)
  613.         ShowWindow(hDlgModeless, SW_HIDE);
  614.     }
  615.  
  616.   bmp_done:
  617.     GlobalUnlock(hrow);
  618.     GlobalFree(hrow);
  619.  
  620.     return code;
  621. }
  622.  
  623. /* combined color mappers */
  624.  
  625. /* 24-bit color mappers (taken from gdevmem2.c). */
  626. /* Note that Windows expects RGB values in the order B,G,R. */
  627.  
  628. /* Map a r-g-b color to a color index. */
  629. private gx_color_index
  630. win_pr2_map_rgb_color(gx_device * dev, gx_color_value r, gx_color_value g,
  631.               gx_color_value b)
  632. {
  633.     switch (dev->color_info.depth) {
  634.     case 1:
  635.         return gdev_prn_map_rgb_color(dev, r, g, b);
  636.     case 4:
  637.         /* use only 8 colors */
  638.         return (r > (gx_max_color_value / 2 + 1) ? 4 : 0) +
  639.         (g > (gx_max_color_value / 2 + 1) ? 2 : 0) +
  640.         (b > (gx_max_color_value / 2 + 1) ? 1 : 0);
  641.     case 8:
  642.         return pc_8bit_map_rgb_color(dev, r, g, b);
  643.     case 24:
  644.         return gx_color_value_to_byte(r) +
  645.         ((uint) gx_color_value_to_byte(g) << 8) +
  646.         ((ulong) gx_color_value_to_byte(b) << 16);
  647.     }
  648.     return 0;            /* error */
  649. }
  650.  
  651. /* Map a color index to a r-g-b color. */
  652. private int
  653. win_pr2_map_color_rgb(gx_device * dev, gx_color_index color,
  654.               gx_color_value prgb[3])
  655. {
  656.     switch (dev->color_info.depth) {
  657.     case 1:
  658.         gdev_prn_map_color_rgb(dev, color, prgb);
  659.         break;
  660.     case 4:
  661.         /* use only 8 colors */
  662.         prgb[0] = (color & 4) ? gx_max_color_value : 0;
  663.         prgb[1] = (color & 2) ? gx_max_color_value : 0;
  664.         prgb[2] = (color & 1) ? gx_max_color_value : 0;
  665.         break;
  666.     case 8:
  667.         pc_8bit_map_color_rgb(dev, color, prgb);
  668.         break;
  669.     case 24:
  670.         prgb[2] = gx_color_value_from_byte(color >> 16);
  671.         prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
  672.         prgb[0] = gx_color_value_from_byte(color & 0xff);
  673.         break;
  674.     }
  675.     return 0;
  676. }
  677.  
  678. void
  679. win_pr2_set_bpp(gx_device * dev, int depth)
  680. {
  681.     if (depth > 8) {
  682.     static const gx_device_color_info win_pr2_24color = dci_std_color(24);
  683.  
  684.     dev->color_info = win_pr2_24color;
  685.     depth = 24;
  686.     } else if (depth >= 8) {
  687.     /* 8-bit (SuperVGA-style) color. */
  688.     /* (Uses a fixed palette of 3,3,2 bits.) */
  689.     static const gx_device_color_info win_pr2_8color = dci_pc_8bit;
  690.  
  691.     dev->color_info = win_pr2_8color;
  692.     depth = 8;
  693.     } else if (depth >= 3) {
  694.     /* 3 plane printer */
  695.     /* suitable for impact dot matrix CMYK printers */
  696.     /* create 4-bit bitmap, but only use 8 colors */
  697.     static const gx_device_color_info win_pr2_4color = dci_values(3, 4, 1, 1, 2, 2);
  698.  
  699.     dev->color_info = win_pr2_4color;
  700.     depth = 4;
  701.     } else {            /* default is black_and_white */
  702.     static const gx_device_color_info win_pr2_1color = dci_std_color(1);
  703.  
  704.     dev->color_info = win_pr2_1color;
  705.     depth = 1;
  706.     }
  707.     
  708.     ((gx_device_win_pr2 *)dev)->selected_bpp = depth;
  709. }
  710.  
  711. /********************************************************************************/
  712.  
  713. /* Get device parameters */
  714. int
  715. win_pr2_get_params(gx_device * pdev, gs_param_list * plist)
  716. {
  717.     int code = gdev_prn_get_params(pdev, plist);
  718.  
  719.     win_pr2_copy_check(wdev);
  720.  
  721.     if (code >= 0)
  722.     code = param_write_bool(plist, "NoCancel",
  723.                 &(wdev->nocancel));
  724.     if (code >= 0)
  725.     code = win_pr2_write_user_settings(wdev, plist);
  726.  
  727.     return code;
  728. }
  729.  
  730.  
  731. /* We implement this ourselves so that we can change BitsPerPixel */
  732. /* before the device is opened */
  733. int
  734. win_pr2_put_params(gx_device * pdev, gs_param_list * plist)
  735. {
  736.     int ecode = 0, code;
  737.     int old_bpp = pdev->color_info.depth;
  738.     int bpp = old_bpp;
  739.     bool nocancel = wdev->nocancel;
  740.     int queryuser = 0;
  741.     bool old_duplex = wdev->Duplex;
  742.     int  old_orient = wdev->user_orient;
  743.     int  old_color  = wdev->user_color;
  744.     int  old_paper  = wdev->user_paper;
  745.     int  old_mx_dpi = wdev->max_dpi;
  746.  
  747.     if (wdev->Duplex_set < 0) {
  748.     wdev->Duplex_set = 0;
  749.     wdev->Duplex = false;
  750.     }
  751.     
  752.     win_pr2_copy_check(wdev);
  753.  
  754.     code = win_pr2_read_user_settings(wdev, plist);
  755.  
  756.     switch (code = param_read_int(plist, "BitsPerPixel", &bpp)) {
  757.     case 0:
  758.         if (pdev->is_open) {
  759.         if (wdev->selected_bpp == bpp) {
  760.             break;
  761.         }
  762.         ecode = gs_error_rangecheck;
  763.         } else {        /* change dev->color_info is valid before device is opened */
  764.         win_pr2_set_bpp(pdev, bpp);
  765.         break;
  766.         }
  767.         goto bppe;
  768.     default:
  769.         ecode = code;
  770.       bppe:param_signal_error(plist, "BitsPerPixel", ecode);
  771.     case 1:
  772.         break;
  773.     }
  774.  
  775.     switch (code = param_read_bool(plist, "NoCancel", &nocancel)) {
  776.     case 0:
  777.         if (pdev->is_open) {
  778.         if (wdev->nocancel == nocancel) {
  779.             break;
  780.         }
  781.         ecode = gs_error_rangecheck;
  782.         } else {
  783.         wdev->nocancel = nocancel;
  784.         break;
  785.         }
  786.         goto nocancele;
  787.     default:
  788.         ecode = code;
  789.       nocancele:param_signal_error(plist, "NoCancel", ecode);
  790.     case 1:
  791.         break;
  792.     }
  793.  
  794.     switch (code = param_read_int(plist, "QueryUser", &queryuser)) {
  795.     case 0:
  796.         if ((queryuser > 0) &&
  797.         (queryuser < 4)) {
  798.         win_pr2_print_setup_interaction(wdev, queryuser);
  799.         }
  800.         break;
  801.     default:
  802.         ecode = code;
  803.         param_signal_error(plist, "QueryUser", ecode);
  804.     case 1:
  805.         break;
  806.     }
  807.  
  808.     if (ecode >= 0)
  809.     ecode = gdev_prn_put_params(pdev, plist);
  810.     
  811.     if (wdev->win32_hdevmode && wdev->hdcprn) {
  812.     if ( (old_duplex != wdev->Duplex)
  813.       || (old_orient != wdev->user_orient)
  814.       || (old_color  != wdev->user_color)
  815.       || (old_paper  != wdev->user_paper)
  816.       || (old_mx_dpi != wdev->max_dpi) ) {
  817.         
  818.         LPDEVMODE pdevmode = GlobalLock(wdev->win32_hdevmode);
  819.         
  820.         if (pdevmode) {
  821.         win_pr2_update_win(wdev, pdevmode);
  822.         ResetDC(wdev->hdcprn, pdevmode);
  823.         GlobalUnlock(pdevmode);
  824.         }
  825.     }
  826.     }
  827.     
  828.     return ecode;
  829. }
  830.  
  831. #undef wdev
  832.  
  833. /********************************************************************************/
  834.  
  835. #ifndef __WIN32__
  836. #include <print.h>
  837. #endif
  838.  
  839. /* Get Device Context for printer */
  840. private int
  841. win_pr2_getdc(gx_device_win_pr2 * wdev)
  842. {
  843.     char *device;
  844.     char *devices;
  845.     char *p;
  846.     char driverbuf[512];
  847.     char *driver;
  848.     char *output;
  849.     char *devcap;
  850.     int devcapsize;
  851.     int size;
  852.  
  853.     int i, n;
  854.     POINT *pp;
  855.     int paperindex;
  856.     int paperwidth, paperheight;
  857.     int orientation;
  858.     int papersize;
  859.     char papername[64];
  860.     char drvname[32];
  861.     HINSTANCE hlib;
  862.     LPFNDEVMODE pfnExtDeviceMode;
  863.     LPFNDEVCAPS pfnDeviceCapabilities;
  864.     LPDEVMODE podevmode, pidevmode;
  865.  
  866. #ifdef __WIN32__
  867.     HANDLE hprinter;
  868. #endif
  869.  
  870.     /* first try to derive the printer name from -sOutputFile= */
  871.     /* is printer if name prefixed by \\spool\ */
  872.     if (is_spool(wdev->fname))
  873.     device = wdev->fname + 8;    /* skip over \\spool\ */
  874.     else
  875.     return FALSE;
  876.  
  877.     /* now try to match the printer name against the [Devices] section */
  878.     if ((devices = gs_malloc(4096, 1, "win_pr2_getdc")) == (char *)NULL)
  879.     return FALSE;
  880.     GetProfileString("Devices", NULL, "", devices, 4096);
  881.     p = devices;
  882.     while (*p) {
  883.     if (stricmp(p, device) == 0)
  884.         break;
  885.     p += strlen(p) + 1;
  886.     }
  887.     if (*p == '\0')
  888.     p = NULL;
  889.     gs_free(devices, 4096, 1, "win_pr2_getdc");
  890.     if (p == NULL)
  891.     return FALSE;        /* doesn't match an available printer */
  892.  
  893.     /* the printer exists, get the remaining information from win.ini */
  894.     GetProfileString("Devices", device, "", driverbuf, sizeof(driverbuf));
  895.     driver = strtok(driverbuf, ",");
  896.     output = strtok(NULL, ",");
  897. #ifdef __WIN32__
  898.     if (is_win32s)
  899. #endif
  900.     {
  901.     strcpy(drvname, driver);
  902.     strcat(drvname, ".drv");
  903.     driver = drvname;
  904.     }
  905. #ifdef __WIN32__
  906.  
  907.     if (!is_win32s) {        /* Win32 */
  908.     if (!OpenPrinter(device, &hprinter, NULL))
  909.         return FALSE;
  910.     size = DocumentProperties(NULL, hprinter, device, NULL, NULL, 0);
  911.     if ((podevmode = gs_malloc(size, 1, "win_pr2_getdc")) == (LPDEVMODE) NULL) {
  912.         ClosePrinter(hprinter);
  913.         return FALSE;
  914.     }
  915.     if ((pidevmode = gs_malloc(size, 1, "win_pr2_getdc")) == (LPDEVMODE) NULL) {
  916.         gs_free(podevmode, size, 1, "win_pr2_getdc");
  917.         ClosePrinter(hprinter);
  918.         return FALSE;
  919.     }
  920.     DocumentProperties(NULL, hprinter, device, podevmode, NULL, DM_OUT_BUFFER);
  921.     pfnDeviceCapabilities = (LPFNDEVCAPS) DeviceCapabilities;
  922.     } else
  923. #endif
  924.     {                /* Win16 and Win32s */
  925.     /* now load the printer driver */
  926.     hlib = LoadLibrary(driver);
  927.     if (hlib < (HINSTANCE) HINSTANCE_ERROR)
  928.         return FALSE;
  929.  
  930.     /* call ExtDeviceMode() to get default parameters */
  931.     pfnExtDeviceMode = (LPFNDEVMODE) GetProcAddress(hlib, "ExtDeviceMode");
  932.     if (pfnExtDeviceMode == (LPFNDEVMODE) NULL) {
  933.         FreeLibrary(hlib);
  934.         return FALSE;
  935.     }
  936.     pfnDeviceCapabilities = (LPFNDEVCAPS) GetProcAddress(hlib, "DeviceCapabilities");
  937.     if (pfnDeviceCapabilities == (LPFNDEVCAPS) NULL) {
  938.         FreeLibrary(hlib);
  939.         return FALSE;
  940.     }
  941.     size = pfnExtDeviceMode(NULL, hlib, NULL, device, output, NULL, NULL, 0);
  942.     if ((podevmode = gs_malloc(size, 1, "win_pr2_getdc")) == (LPDEVMODE) NULL) {
  943.         FreeLibrary(hlib);
  944.         return FALSE;
  945.     }
  946.     if ((pidevmode = gs_malloc(size, 1, "win_pr2_getdc")) == (LPDEVMODE) NULL) {
  947.         gs_free(podevmode, size, 1, "win_pr2_getdc");
  948.         FreeLibrary(hlib);
  949.         return FALSE;
  950.     }
  951.     pfnExtDeviceMode(NULL, hlib, podevmode, device, output,
  952.              NULL, NULL, DM_OUT_BUFFER);
  953.     }
  954.  
  955.     /* now find out what paper sizes are available */
  956.     devcapsize = pfnDeviceCapabilities(device, output, DC_PAPERSIZE, NULL, NULL);
  957.     devcapsize *= sizeof(POINT);
  958.     if ((devcap = gs_malloc(devcapsize, 1, "win_pr2_getdc")) == (LPBYTE) NULL)
  959.     return FALSE;
  960.     n = pfnDeviceCapabilities(device, output, DC_PAPERSIZE, devcap, NULL);
  961.     paperwidth = (int)(wdev->MediaSize[0] * 254 / 72);
  962.     paperheight = (int)(wdev->MediaSize[1] * 254 / 72);
  963.     papername[0] = '\0';
  964.     papersize = 0;
  965.     paperindex = -1;
  966.     orientation = 0;
  967.     pp = (POINT *) devcap;
  968.     for (i = 0; i < n; i++, pp++) {
  969.     if ((pp->x < paperwidth + 20) && (pp->x > paperwidth - 20) &&
  970.         (pp->y < paperheight + 20) && (pp->y > paperheight - 20)) {
  971.         paperindex = i;
  972.         paperwidth = pp->x;
  973.         paperheight = pp->y;
  974.         orientation = DMORIENT_PORTRAIT;
  975.         break;
  976.     }
  977.     }
  978.     if (paperindex < 0) {
  979.     /* try again in landscape */
  980.     pp = (POINT *) devcap;
  981.     for (i = 0; i < n; i++, pp++) {
  982.         if ((pp->x < paperheight + 20) && (pp->x > paperheight - 20) &&
  983.         (pp->y < paperwidth + 20) && (pp->y > paperwidth - 20)) {
  984.         paperindex = i;
  985.         paperwidth = pp->x;
  986.         paperheight = pp->y;
  987.         orientation = DMORIENT_LANDSCAPE;
  988.         break;
  989.         }
  990.     }
  991.     }
  992.     gs_free(devcap, devcapsize, 1, "win_pr2_getdc");
  993.     
  994.     /* get the dmPaperSize */
  995.     devcapsize = pfnDeviceCapabilities(device, output, DC_PAPERS, NULL, NULL);
  996.     devcapsize *= sizeof(WORD);
  997.     if ((devcap = gs_malloc(devcapsize, 1, "win_pr2_getdc")) == (LPBYTE) NULL)
  998.     return FALSE;
  999.     n = pfnDeviceCapabilities(device, output, DC_PAPERS, devcap, NULL);
  1000.     if ((paperindex >= 0) && (paperindex < n))
  1001.     papersize = ((WORD *) devcap)[paperindex];
  1002.     gs_free(devcap, devcapsize, 1, "win_pr2_getdc");
  1003.  
  1004.     /* get the paper name */
  1005.     devcapsize = pfnDeviceCapabilities(device, output, DC_PAPERNAMES, NULL, NULL);
  1006.     devcapsize *= 64;
  1007.     if ((devcap = gs_malloc(devcapsize, 1, "win_pr2_getdc")) == (LPBYTE) NULL)
  1008.     return FALSE;
  1009.     n = pfnDeviceCapabilities(device, output, DC_PAPERNAMES, devcap, NULL);
  1010.     if ((paperindex >= 0) && (paperindex < n))
  1011.     strcpy(papername, devcap + paperindex * 64);
  1012.     gs_free(devcap, devcapsize, 1, "win_pr2_getdc");
  1013.  
  1014.     memcpy(pidevmode, podevmode, size);
  1015.  
  1016.     pidevmode->dmFields = 0;
  1017.     
  1018.     wdev->paper_name[0] = 0;
  1019.  
  1020.     if ( (wdev->user_paper)
  1021.       && (wdev->user_paper != papersize) ) {
  1022.     papersize = wdev->user_paper;
  1023.     paperheight = 0;
  1024.     paperwidth = 0;
  1025.     papername[0] = 0;
  1026.     }
  1027.     if (wdev->user_orient) {
  1028.     orientation = wdev->user_orient;
  1029.     }
  1030.     
  1031.     pidevmode->dmFields &= ~(DM_PAPERSIZE | DM_ORIENTATION | DM_COLOR | DM_PAPERLENGTH | DM_PAPERWIDTH | DM_DUPLEX);
  1032.     pidevmode->dmFields |= DM_DEFAULTSOURCE;
  1033.     pidevmode->dmDefaultSource = 0;
  1034.     
  1035.     if (orientation) {
  1036.     wdev->user_orient = orientation;
  1037.     }
  1038.     if (papersize) {
  1039.     wdev->user_paper = papersize;
  1040.     strcpy (wdev->paper_name, papername);
  1041.     }
  1042.     
  1043.     if (paperheight && paperwidth) {
  1044.     pidevmode->dmFields |= (DM_PAPERLENGTH | DM_PAPERWIDTH);
  1045.     pidevmode->dmPaperWidth = paperwidth;
  1046.     pidevmode->dmPaperLength = paperheight;
  1047.         wdev->user_media_size[0] = paperwidth / 254.0 * 72.0;
  1048.     wdev->user_media_size[1] = paperheight / 254.0 * 72.0;
  1049.     }
  1050.     
  1051.     if (DeviceCapabilities(device, output, DC_DUPLEX, NULL, NULL)) {
  1052.     wdev->Duplex_set = 1;
  1053.     }
  1054.     
  1055.     win_pr2_update_win(wdev, pidevmode);
  1056.     
  1057. #ifdef WIN32
  1058.     if (!is_win32s) {
  1059.     
  1060.     /* merge the entries */
  1061.     DocumentProperties(NULL, hprinter, device, podevmode, pidevmode, DM_IN_BUFFER | DM_OUT_BUFFER);
  1062.     ClosePrinter(hprinter);
  1063.     
  1064.     /* now get a DC */
  1065.     wdev->hdcprn = CreateDC(driver, device, NULL, podevmode);
  1066.     } else
  1067. #endif
  1068.     {                /* Win16 and Win32s */
  1069.     pfnExtDeviceMode(NULL, hlib, podevmode, device, output,
  1070.              pidevmode, NULL, DM_IN_BUFFER | DM_OUT_BUFFER);
  1071.     /* release the printer driver */
  1072.     FreeLibrary(hlib);
  1073.     /* now get a DC */
  1074.     if (is_win32s)
  1075.         strtok(driver, ".");    /* remove .drv */
  1076.     wdev->hdcprn = CreateDC(driver, device, output, podevmode);
  1077.     }
  1078.     
  1079.     if (wdev->win32_hdevmode == NULL) {
  1080.     wdev->win32_hdevmode = GlobalAlloc(0, sizeof(DEVMODE));
  1081.     }
  1082.     
  1083.     if (wdev->win32_hdevmode) {
  1084.     LPDEVMODE pdevmode = (LPDEVMODE) GlobalLock(GlobalLock(wdev->win32_hdevmode));
  1085.     if (pdevmode) {
  1086.         memcpy(pdevmode, podevmode, sizeof(DEVMODE));
  1087.         GlobalUnlock(wdev->win32_hdevmode);
  1088.     }
  1089.     }
  1090.  
  1091.     gs_free(pidevmode, size, 1, "win_pr2_getdc");
  1092.     gs_free(podevmode, size, 1, "win_pr2_getdc");
  1093.  
  1094.     if (wdev->hdcprn != (HDC) NULL)
  1095.     return TRUE;        /* success */
  1096.  
  1097.     /* fall back to prompting user */
  1098.     return FALSE;
  1099. }
  1100.  
  1101.  
  1102. /*
  1103.  *  Minimalist update of the wdev parameters (mainly for the
  1104.  *  UserSettings parameters).
  1105.  */
  1106.  
  1107. private int
  1108. win_pr2_update_dev(gx_device_win_pr2 * dev, LPDEVMODE pdevmode)
  1109. {
  1110.     if (pdevmode == 0)
  1111.     return FALSE;
  1112.     
  1113.     if (pdevmode->dmFields & DM_COLOR) {
  1114.     dev->user_color = pdevmode->dmColor;
  1115.     }
  1116.     if (pdevmode->dmFields & DM_ORIENTATION) {
  1117.     dev->user_orient = pdevmode->dmOrientation;
  1118.     }
  1119.     if (pdevmode->dmFields & DM_PAPERSIZE) {
  1120.     dev->user_paper = pdevmode->dmPaperSize;
  1121.         dev->user_media_size[0] = pdevmode->dmPaperWidth / 254.0 * 72.0;
  1122.     dev->user_media_size[1] = pdevmode->dmPaperLength / 254.0 * 72.0;
  1123.     dev->paper_name[0] = 0;        /* unknown paper size */
  1124.     }
  1125.     if (pdevmode->dmFields & DM_DUPLEX) {
  1126.     dev->Duplex_set = 1;
  1127.     dev->Duplex = pdevmode->dmDuplex == DMDUP_SIMPLEX ? false : true;
  1128.     }
  1129.     
  1130.     return TRUE;
  1131. }
  1132.  
  1133. private int
  1134. win_pr2_update_win(gx_device_win_pr2 * dev, LPDEVMODE pdevmode)
  1135. {
  1136.     if (dev->Duplex_set > 0) {
  1137.     pdevmode->dmFields |= DM_DUPLEX;
  1138.     pdevmode->dmDuplex = DMDUP_SIMPLEX;
  1139.     if (dev->Duplex) {
  1140. /*        if (dev->Tumble) {
  1141.         pdevmode->dmDuplex = DMDUP_VERTICAL;
  1142.         } else */ {
  1143.         pdevmode->dmDuplex = DMDUP_HORIZONTAL;
  1144.         }
  1145.     }
  1146.     }
  1147.     
  1148.     if (dev->user_color) {
  1149.     pdevmode->dmColor = dev->user_color;
  1150.     pdevmode->dmFields |= DM_COLOR;
  1151.     }
  1152.     
  1153.     if (dev->user_orient) {
  1154.     pdevmode->dmFields |= DM_ORIENTATION;
  1155.     pdevmode->dmOrientation = dev->user_orient;
  1156.     }
  1157.     
  1158.     if (dev->user_paper) {
  1159.     pdevmode->dmFields |= DM_PAPERSIZE;
  1160.     pdevmode->dmPaperSize = dev->user_paper;
  1161.     }
  1162. }
  1163.  
  1164. /********************************************************************************/
  1165.  
  1166. #define BEGIN_ARRAY_PARAM(pread, pname, pa, psize, e)\
  1167.   switch ( code = pread(dict.list, (param_name = pname), &(pa)) )\
  1168.   {\
  1169.   case 0:\
  1170.     if ( (pa).size != psize )\
  1171.       ecode = gs_note_error(gs_error_rangecheck);\
  1172.     else {
  1173. /* The body of the processing code goes here. */
  1174. /* If it succeeds, it should do a 'break'; */
  1175. /* if it fails, it should set ecode and fall through. */
  1176. #define END_ARRAY_PARAM(pa, e)\
  1177.     }\
  1178.     goto e;\
  1179.   default:\
  1180.     ecode = code;\
  1181. e:    param_signal_error(dict.list, param_name, ecode);\
  1182.   case 1:\
  1183.     (pa).data = 0;        /* mark as not filled */\
  1184.   }
  1185.  
  1186.  
  1187. /* Put the user params from UserSettings into our */
  1188. /* internal variables. */
  1189. private int
  1190. win_pr2_read_user_settings(gx_device_win_pr2 * wdev, gs_param_list * plist)
  1191. {
  1192.     gs_param_dict dict;
  1193.     gs_param_string docn = { 0 };
  1194.     const char* dict_name = "UserSettings";
  1195.     const char* param_name = "";
  1196.     int code = 0;
  1197.     int ecode = 0;
  1198.  
  1199.     switch (code = param_begin_read_dict(plist, dict_name, &dict, false)) {
  1200.     default:
  1201.         param_signal_error(plist, dict_name, code);
  1202.         return code;
  1203.     case 1:
  1204.         break;
  1205.     case 0:
  1206.         {
  1207.         gs_param_int_array ia;
  1208.         
  1209.         BEGIN_ARRAY_PARAM(param_read_int_array, "DocumentRange", ia, 2, ia)
  1210.         if ((ia.data[0] < 0) ||
  1211.             (ia.data[1] < 0) ||
  1212.             (ia.data[0] > ia.data[1]))
  1213.             ecode = gs_note_error(gs_error_rangecheck);
  1214.         wdev->doc_page_begin = ia.data[0];
  1215.         wdev->doc_page_end = ia.data[1];
  1216.         END_ARRAY_PARAM(ia, doc_range_error)
  1217.         
  1218.         BEGIN_ARRAY_PARAM(param_read_int_array, "SelectedRange", ia, 2, ia)
  1219.         if ((ia.data[0] < 0) ||
  1220.             (ia.data[1] < 0) ||
  1221.             (ia.data[0] > ia.data[1]))
  1222.             ecode = gs_note_error(gs_error_rangecheck);
  1223.         wdev->user_page_begin = ia.data[0];
  1224.         wdev->user_page_end = ia.data[1];
  1225.         END_ARRAY_PARAM(ia, sel_range_error)
  1226.         
  1227.         param_read_int(dict.list, "Copies", &wdev->user_copies);
  1228.         param_read_int(dict.list, "Paper", &wdev->user_paper);
  1229.         param_read_int(dict.list, "Orientation", &wdev->user_orient);
  1230.         param_read_int(dict.list, "Color", &wdev->user_color);
  1231.         param_read_int(dict.list, "MaxResolution", &wdev->max_dpi);
  1232.         
  1233.         switch (code = param_read_string(dict.list, (param_name = "DocumentName"), &docn)) {
  1234.             case 0:
  1235.             if (docn.size < sizeof(wdev->doc_name))
  1236.                 break;
  1237.             code = gs_error_rangecheck;
  1238.             /* fall through */
  1239.             default:
  1240.             ecode = code;
  1241.             param_signal_error(plist, param_name, ecode);
  1242.             /* fall through */
  1243.             case 1:
  1244.             docn.data = 0;
  1245.             break;
  1246.         }
  1247.         
  1248.         param_end_read_dict(plist, dict_name, &dict);
  1249.         
  1250.         if (docn.data) {
  1251.             memcpy(wdev->doc_name, docn.data, docn.size);
  1252.             wdev->doc_name[docn.size] = 0;
  1253.         }
  1254.         
  1255.         wdev->print_copies = 1;
  1256.         
  1257.         if (wdev->win32_hdevmode) {
  1258.             LPDEVMODE devmode = (LPDEVMODE) GlobalLock(wdev->win32_hdevmode);
  1259.             if (devmode) {
  1260.             devmode->dmCopies = wdev->user_copies;
  1261.             devmode->dmPaperSize = wdev->user_paper;
  1262.             devmode->dmOrientation = wdev->user_orient;
  1263.             devmode->dmColor = wdev->user_color;
  1264.             GlobalUnlock(wdev->win32_hdevmode);
  1265.             }
  1266.         }
  1267.         }
  1268.         break;
  1269.     }
  1270.  
  1271.     return code;
  1272. }
  1273.  
  1274.  
  1275. private int
  1276. win_pr2_write_user_settings(gx_device_win_pr2 * wdev, gs_param_list * plist)
  1277. {
  1278.     gs_param_dict dict;
  1279.     gs_param_int_array range;
  1280.     gs_param_float_array box;
  1281.     gs_param_string docn;
  1282.     gs_param_string papn;
  1283.     int array[2];
  1284.     const char* pname = "UserSettings";
  1285.     int code;
  1286.  
  1287.     dict.size = 12;
  1288.     code = param_begin_write_dict(plist, pname, &dict, false);
  1289.     if (code < 0) return code;
  1290.  
  1291.     array[0] = wdev->doc_page_begin;
  1292.     array[1] = wdev->doc_page_end;
  1293.     range.data = array;
  1294.     range.size = 2;
  1295.     range.persistent = false;
  1296.     code = param_write_int_array(dict.list, "DocumentRange", &range);
  1297.     if (code < 0) goto error;
  1298.  
  1299.     array[0] = wdev->user_page_begin;
  1300.     array[1] = wdev->user_page_end;
  1301.     range.data = array;
  1302.     range.size = 2;
  1303.     range.persistent = false;
  1304.     code = param_write_int_array(dict.list, "SelectedRange", &range);
  1305.     if (code < 0) goto error;
  1306.  
  1307.     box.data = wdev->user_media_size;
  1308.     box.size = 2;
  1309.     box.persistent = false;
  1310.     code = param_write_float_array(dict.list, "MediaSize", &box);
  1311.     if (code < 0) goto error;
  1312.  
  1313.     code = param_write_int(dict.list, "Copies", &wdev->user_copies);
  1314.     if (code < 0) goto error;
  1315.  
  1316.     code = param_write_int(dict.list, "Paper", &wdev->user_paper);
  1317.     if (code < 0) goto error;
  1318.     
  1319.     code = param_write_int(dict.list, "Orientation", &wdev->user_orient);
  1320.     if (code < 0) goto error;
  1321.     
  1322.     code = param_write_int(dict.list, "Color", &wdev->user_color);
  1323.     if (code < 0) goto error;
  1324.     
  1325.     code = param_write_int(dict.list, "MaxResolution", &wdev->max_dpi);
  1326.     if (code < 0) goto error;
  1327.     
  1328.     code = param_write_int(dict.list, "PrintCopies", &wdev->print_copies);
  1329.     if (code < 0) goto error;
  1330.  
  1331.     docn.data = (const byte*)wdev->doc_name;
  1332.     docn.size = strlen(wdev->doc_name);
  1333.     docn.persistent = false;
  1334.  
  1335.     code = param_write_string(dict.list, "DocumentName", &docn);
  1336.     if (code < 0) goto error;
  1337.     
  1338.     papn.data = (const byte*)wdev->paper_name;
  1339.     papn.size = strlen(wdev->paper_name);
  1340.     papn.persistent = false;
  1341.     
  1342.     code = param_write_string(dict.list, "PaperName", &papn);
  1343.     if (code < 0) goto error;
  1344.  
  1345.     code = param_write_bool(dict.list, "UserChangedSettings", &wdev->user_changed_settings);
  1346.  
  1347. error:
  1348.     param_end_write_dict(plist, pname, &dict);
  1349.     return code;
  1350. }
  1351.  
  1352. /********************************************************************************/
  1353.  
  1354. /*  Show up a dialog for the user to choose a printer and a paper size.
  1355.  *  If mode == 3, then automatically select the default Windows printer
  1356.  *  instead of asking the user.
  1357.  */
  1358.  
  1359. private int
  1360. win_pr2_print_setup_interaction(gx_device_win_pr2 * wdev, int mode)
  1361. {
  1362.     PRINTDLG pd;
  1363.     LPDEVMODE  devmode;
  1364.     LPDEVNAMES devnames;
  1365.  
  1366.     wdev->user_changed_settings = FALSE;
  1367.  
  1368.     memset(&pd, 0, sizeof(pd));
  1369.     pd.lStructSize = sizeof(pd);
  1370.     pd.hwndOwner = hwndtext;
  1371.  
  1372.     switch (mode) {
  1373.     case 2:    pd.Flags = PD_PRINTSETUP; break;
  1374.     case 3:    pd.Flags = PD_RETURNDEFAULT; break;
  1375.     default: pd.Flags = 0; break;
  1376.     }
  1377.  
  1378.     pd.Flags |= PD_USEDEVMODECOPIES;
  1379.  
  1380.     pd.nMinPage = wdev->doc_page_begin;
  1381.     pd.nMaxPage = wdev->doc_page_end;
  1382.     pd.nFromPage = wdev->user_page_begin;
  1383.     pd.nToPage = wdev->user_page_end;
  1384.     pd.nCopies = wdev->user_copies;
  1385.  
  1386.     /* Show the Print Setup dialog and let the user choose a printer
  1387.      * and a paper size/orientation.
  1388.      */
  1389.  
  1390.     if (!PrintDlg(&pd)) return FALSE;
  1391.  
  1392.     devmode = (LPDEVMODE) GlobalLock(pd.hDevMode);
  1393.     devnames = (LPDEVNAMES) GlobalLock(pd.hDevNames);
  1394.  
  1395.     wdev->user_changed_settings = TRUE;
  1396.     sprintf(wdev->fname, "\\\\spool\\%s", (char*)(devnames)+(devnames->wDeviceOffset));
  1397.  
  1398.     if (mode == 3) {
  1399.     devmode->dmCopies = wdev->user_copies * wdev->print_copies;
  1400.     pd.nCopies = 1;
  1401.     }
  1402.  
  1403.     wdev->user_page_begin = pd.nFromPage;
  1404.     wdev->user_page_end = pd.nToPage;
  1405.     wdev->user_copies = devmode->dmCopies;
  1406.     wdev->print_copies = pd.nCopies;
  1407.     wdev->user_media_size[0] = devmode->dmPaperWidth / 254.0 * 72.0;
  1408.     wdev->user_media_size[1] = devmode->dmPaperLength / 254.0 * 72.0;
  1409.     wdev->user_paper = devmode->dmPaperSize;
  1410.     wdev->user_orient = devmode->dmOrientation;
  1411.     wdev->user_color = devmode->dmColor;
  1412.     
  1413.     if (devmode->dmFields & DM_DUPLEX) {
  1414.     wdev->Duplex_set = 1;
  1415.     wdev->Duplex = devmode->dmDuplex == DMDUP_SIMPLEX ? false : true;
  1416.     }
  1417.  
  1418.     {
  1419.     float xppinch = 0;
  1420.     float yppinch = 0;
  1421.     const char* driver = (char*)(devnames)+(devnames->wDriverOffset);
  1422.     const char* device = (char*)(devnames)+(devnames->wDeviceOffset);
  1423.     const char* output = (char*)(devnames)+(devnames->wOutputOffset);
  1424.     
  1425.     HDC hic = CreateIC(driver, device, output, devmode);
  1426.     
  1427.     if (hic) {
  1428.         xppinch = (float)GetDeviceCaps(hic, LOGPIXELSX);
  1429.         yppinch = (float)GetDeviceCaps(hic, LOGPIXELSY);
  1430.         wdev->user_media_size[0] = GetDeviceCaps(hic, PHYSICALWIDTH) * 72.0 / xppinch;
  1431.         wdev->user_media_size[1] = GetDeviceCaps(hic, PHYSICALHEIGHT) * 72.0 / yppinch;
  1432.         DeleteDC(hic);
  1433.     }
  1434.     }
  1435.  
  1436.     devmode = NULL;
  1437.     devnames = NULL;
  1438.  
  1439.     GlobalUnlock(pd.hDevMode);
  1440.     GlobalUnlock(pd.hDevNames);
  1441.  
  1442.     if (wdev->win32_hdevmode != NULL) {
  1443.     GlobalFree(wdev->win32_hdevmode);
  1444.     }
  1445.     if (wdev->win32_hdevnames != NULL) {
  1446.     GlobalFree(wdev->win32_hdevnames);
  1447.     }
  1448.  
  1449.     wdev->win32_hdevmode = pd.hDevMode;
  1450.     wdev->win32_hdevnames = pd.hDevNames;
  1451.  
  1452.     return TRUE;
  1453. }
  1454.  
  1455. /*  Check that we are dealing with an original device. If this
  1456.  *  happens to be a copy made by "copydevice", we will have to
  1457.  *  copy the original's handles to the associated Win32 params.
  1458.  */
  1459.  
  1460. private void
  1461. win_pr2_copy_check(gx_device_win_pr2 * wdev)
  1462. {
  1463.     HGLOBAL hdevmode = wdev->win32_hdevmode;
  1464.     HGLOBAL hdevnames = wdev->win32_hdevnames;
  1465.     DWORD devmode_len = (hdevmode) ? GlobalSize(hdevmode) : 0;
  1466.     DWORD devnames_len = (hdevnames) ? GlobalSize(hdevnames) : 0;
  1467.  
  1468.     if (wdev->original_device == wdev)
  1469.     return;
  1470.  
  1471.     wdev->hdcprn = NULL;
  1472.     wdev->win32_hdevmode = NULL;
  1473.     wdev->win32_hdevnames = NULL;
  1474.  
  1475.     wdev->original_device = wdev;
  1476.  
  1477.     if (devmode_len) {
  1478.     wdev->win32_hdevmode = GlobalAlloc(0, devmode_len);
  1479.     if (wdev->win32_hdevmode) {
  1480.         memcpy(GlobalLock(wdev->win32_hdevmode), GlobalLock(hdevmode), devmode_len);
  1481.         GlobalUnlock(wdev->win32_hdevmode);
  1482.         GlobalUnlock(hdevmode);
  1483.     }
  1484.     }
  1485.  
  1486.     if (devnames_len) {
  1487.     wdev->win32_hdevnames = GlobalAlloc(0, devnames_len);
  1488.     if (wdev->win32_hdevnames) {
  1489.         memcpy(GlobalLock(wdev->win32_hdevnames), GlobalLock(hdevnames), devnames_len);
  1490.         GlobalUnlock(wdev->win32_hdevnames);
  1491.         GlobalUnlock(hdevnames);
  1492.     }
  1493.     }
  1494. }
  1495.